﻿// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php

using System;
using System.Collections.Generic;
using System.Reflection;

using Nova.CodeDOM;
using Nova.Utilities;

namespace Nova.UI
{
    /// <summary>
    /// The view model for a <see cref="CodeDOM.ConstructorRef"/>.
    /// </summary>
    public class ConstructorRefVM : MethodRefVM
    {
        #region /* STATICS */

        internal static new void AddViewModelMapping()
        {
            CreateViewModel.Add(typeof(ConstructorRef),
                delegate(CodeObject codeObject, bool isDescription, Dictionary<CodeObject, CodeObjectVM> dictionary) { return new ConstructorRefVM((ConstructorRef)codeObject, dictionary); });
        }

        #endregion

        #region /* CONSTRUCTORS */

        /// <summary>
        /// Create a view model instance for the specified <see cref="CodeDOM.ConstructorRef"/>.
        /// </summary>
        public ConstructorRefVM(ConstructorRef constructorRef, Dictionary<CodeObject, CodeObjectVM> dictionary)
            : base(constructorRef, dictionary)
        { }

        #endregion

        #region /* PROPERTIES */

        /// <summary>
        /// The underlying <see cref="CodeDOM.ConstructorRef"/> model.
        /// </summary>
        public ConstructorRef ConstructorRef
        {
            get { return (ConstructorRef)CodeObject; }
        }

        #endregion

        #region /* METHODS */

        #endregion

        #region /* RENDERING */

        public override void RenderExpression(CodeRenderer renderer, RenderFlags flags)
        {
            // Display constructors as their declaring type name, including any type arguments (this
            // is the easy way to display them with the proper type arguments and any enclosing types,
            // if appropriate).  However, we must use this object as the tag object for the GUI!
            TypeRefBase typeRef = ConstructorRef.GetDeclaringType();
            if (typeRef != null)
                ((TypeRefVM)CreateVM(typeRef)).RenderType(renderer, _typeArgumentVMs, flags, this);
            else if (ConstructorRef.Reference is ConstructorDecl)
            {
                // If we failed to get the declaring type, and we have an "orphaned" ConstructorDecl,
                // go ahead and display it's name.
                renderer.RenderName(((ConstructorDecl)ConstructorRef.Reference).Name, TYPE_BRUSH, this, flags);
            }
        }

        public static void RenderConstructorInfo(CodeRenderer renderer, ConstructorInfo constructorInfo, RenderFlags flags, CodeObjectVM tag)
        {
            RenderFlags passFlags = flags & ~RenderFlags.Description;
            bool hasBorder = flags.HasFlag(RenderFlags.ForceBorder);
            if (hasBorder)
                renderer.CreateBorder(MethodDeclBaseVM.StaticBorderBrush, MethodDeclBaseVM.StaticBackgroundBrush, tag);

            if (!flags.HasFlag(RenderFlags.NoPreAnnotations))
                AttributeVM.RenderAttributes(renderer, constructorInfo, tag);
            renderer.RenderText(ModifiersHelpers.AsString(MethodRef.GetMethodModifiers(constructorInfo)), KEYWORD_BRUSH, tag);
            RenderTypeAsTypeRefVM(renderer, constructorInfo.DeclaringType, passFlags, tag);  // Render as TypeRefVM for nested tooltips
            DotVM.RenderDot(renderer, tag);

            Type declaringType = constructorInfo.DeclaringType;
            if (declaringType != null)
                renderer.RenderName(declaringType.IsGenericType ? TypeUtil.NonGenericName(declaringType) : declaringType.Name, TYPE_BRUSH, tag, passFlags);
            RenderMethodParameters(renderer, constructorInfo, flags, tag);

            // If we have a border, return to the previous one
            if (hasBorder)
                renderer.ReturnToBorderParent(tag);
        }

        /// <summary>
        /// Render a ConstructorInfo as a ConstructorRefVM for nested tooltips.
        /// </summary>
        public static void RenderConstructorInfoAsConstructorRefVM(CodeRenderer renderer, ConstructorInfo constructorInfo, RenderFlags flags, CodeObjectVM parentVM)
        {
            // Use parentVM to render if possible, but it can be null if we're inside a tooltip
            CodeObjectVM codeObjectVM;
            MethodRef methodRef = MethodRef.Create(constructorInfo);
            if (parentVM != null)
                codeObjectVM = parentVM.CreateVM(methodRef, true);
            else
                codeObjectVM = CreateVM(methodRef, null, true);
            codeObjectVM.Render(renderer, flags | RenderFlags.NoBorder);
        }

        #endregion
    }
}
